package com.baohulu.baohulu.utils;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import android.util.Log;

import com.baohulu.baohulu.R;
import com.baohulu.baohulu.activity.account.AccountActivity;
import com.baohulu.baohulu.base.BaseResponseCallback;
import com.baohulu.baohulu.common.Const;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

/**
 * 网络请求工具类
 * Created by wenhaiz on 2018/3/18.
 */

public class HttpUtil {
    public static final String COOKIE_PREF = "cookie_pref";
    private static final String TAG = "HttpUtil";
    private static final MediaType JSON
            = MediaType.parse("application/json");

    /**
     * HTTP GET 请求
     *
     * @param activity activity
     * @param url      url
     * @param callback 回调接口
     */
    @SuppressWarnings("unused")
    public static void get(final Activity activity, String url, final BaseResponseCallback callback) {
        if (isNetworkNotAvailable(activity)) {
            callback.onFailure(activity.getString(R.string.no_network));
            return;
        }
        callback.onStart();
        Request request = new Request.Builder()
                .url(url)
                .get()
                .build();
        Log.d(TAG, "get: url=" + url);
        Call call = getHttpClient().newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(@NonNull Call call, @NonNull final IOException e) {
                onResponseFailure(e.getLocalizedMessage(), callback, activity);
            }

            @Override
            public void onResponse(@NonNull Call call, @NonNull final Response response) {
                onRawResponse(call, response, callback, activity);
            }
        });
    }

    /**
     * 检查网络是否连接
     *
     * @param context 上下文
     * @return 连接：true;未连接：false
     */
    @SuppressWarnings("ConstantConditions")
    private static boolean isNetworkNotAvailable(Context context) {
        ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
        return networkInfo == null || !networkInfo.isConnected();
    }

    private static OkHttpClient getHttpClient() {
        return SingletonHolder.INSTANCE;
    }

    private static void onResponseFailure(final String errorMsg, final BaseResponseCallback callback, final Activity activity) {
        activity.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                callback.onFailure(errorMsg);
            }
        });
    }

    /**
     * 对原始响应进行处理
     *
     * @param response http响应
     * @param callback 回调接口
     */
    @SuppressWarnings("ConstantConditions")
    private static void onRawResponse(Call call, final Response response, final BaseResponseCallback callback, final Activity activity) {
        if (call.isCanceled()) {
            callback.onCanceled();
            Log.i(TAG, "onRawResponse: request call has been canceled,so ignore the response!");
            return;
        }

        if (response.isSuccessful() && response.body() != null) {//请求成功
            onResponseSuccess(response, callback, activity);
        } else {//请求失败
            onResponseFailure(response.message(), callback, activity);
        }
    }

    /**
     * 对有效响应进行处理
     *
     * @param response 响应
     * @param callback 回调
     * @param activity activity
     */
    private static void onResponseSuccess(Response response, final BaseResponseCallback callback, final Activity activity) {
        final String bodyString = getResponseString(response);
        if (TextUtils.isEmpty(bodyString)) {
            onResponseFailure("解析响应字符出错", callback, activity);
        } else {
            activity.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    onStringResponse(bodyString, callback, activity);
                }
            });
        }

    }

    @SuppressWarnings("ConstantConditions")
    private static String getResponseString(Response response) {
        String bodyString;
        try {
            bodyString = response.body().string();
        } catch (IOException e) {
            Log.e(TAG, "getResponseString: ", e);
            return null;
        }
        return bodyString;
    }

    /**
     * 对响应字符串进行判断并调用响应处理方法
     *
     * @param bodyString 响应字符串
     * @param callback   回调
     * @param activity   activity
     */
    private static void onStringResponse(final String bodyString, final BaseResponseCallback callback, final Activity activity) {
        try {
            if (bodyString.startsWith("{") && bodyString.endsWith("}")) {//JSONObject
                JSONObject object = new JSONObject(bodyString);
                onJSONObjectResponse(object, callback, activity);
            } else if (bodyString.startsWith("[") && bodyString.endsWith("]")) {//JSONArray
                callback.onJsonArrayResponse(new JSONArray(bodyString));
            }
        } catch (JSONException e) {
            Log.e(TAG, "onStringResponse: " + e.getLocalizedMessage());
            //直接处理字符串
            callback.onResponse(bodyString);
        }
    }

    /**
     * 对响应的JSONObject进行处理
     *
     * @param object   JSONObject
     * @param callback 回调
     * @param activity activity
     */
    private static void onJSONObjectResponse(JSONObject object, BaseResponseCallback callback, Activity activity) {
        int state = 0;
        try {
            state = object.getInt("state");
        } catch (JSONException e) {
            Log.e(TAG, "onJSONObjectResponse: ", e);
        }
        if (state == -1) {//用户未登录或者session 过期
            callback.onCanceled();
            //取消所有后续请求
            getHttpClient().dispatcher().cancelAll();

            ToastUtil.showToast(R.string.please_login_again);
            activity.startActivity(new Intent(activity, AccountActivity.class));
            SharedPrefUtil.clearLoginState();
        } else {
            //调用回调接口
            callback.onJsonObjectResponse(object);
        }

    }

    public static void post(final Activity activity, String url, JSONObject json, final BaseResponseCallback callback) {
        if (isNetworkNotAvailable(activity)) {
            callback.onFailure(activity.getString(R.string.no_network));
            return;
        }

        callback.onStart();
        RequestBody requestBody = RequestBody.create(JSON, json.toString());
        // TODO: 2018/4/21 方便测试，记得删除下面这句
        url = getUrlWithCustomIPAddress(url);
        Request postRequest = new Request.Builder()
                .url(url)
                .post(requestBody)
                .build();
        Log.d(TAG, "post: url=" + url + " ,post data:" + json.toString());
        getHttpClient().newCall(postRequest).enqueue(new Callback() {
            @Override
            public void onFailure(@NonNull Call call, @NonNull final IOException e) {
                onResponseFailure(e.getLocalizedMessage(), callback, activity);
            }

            @Override
            public void onResponse(@NonNull Call call, @NonNull final Response response) {
                onRawResponse(call, response, callback, activity);
            }
        });
    }

    /**
     * 获取根据自定义IP生成URL，方便测试
     *
     * @param oldUrl 旧url
     * @return 新的url
     */
    private static String getUrlWithCustomIPAddress(String oldUrl) {
        String result = oldUrl;
        boolean customIp = SharedPrefUtil.getBoolean(Const.SpKey.IS_CUSTOM_IP);
        if (customIp) {
            String ip = SharedPrefUtil.getString(Const.SpKey.CUSTOM_IP);
            String urlPattern = "(\\w+)://([a-z0-9A-Z_.]+)/(.*)";
            Matcher matcher = Pattern.compile(urlPattern).matcher(oldUrl);
            if (matcher.matches()) {
                result = "http://" + ip + "/" + matcher.group(3);
            } else {
                throw new IllegalArgumentException("URL 格式不合法！");
            }
        }
        return result;
    }

    /**
     * 采用静态内部类方式实现单例
     */
    private static class SingletonHolder {
        private static final OkHttpClient INSTANCE = new OkHttpClient.Builder()
                .connectTimeout(10, TimeUnit.SECONDS)
                .addInterceptor(new SaveCookiesInterceptor())
                .addInterceptor(new LoadCookiesInterceptor())
                .build();
    }
}